[ACM] AWSの無料サーバ証明書の発行と組込をCloudFormationで試してみた
はじめに
AWSチームのすずきです。
先日、2016年8月9日のアップデートにより、CloudFormation が、AWSのサーバ証明書発行サービスACM(AWS Certificate Manager)に対応し、 無料のサーバ証明書の作成と、ELB、CloudFrontへのサーバ証明書の組み込みを、CloudFormationで実施する事が可能になりました。
今回、その内容について紹介させていただきます。
ACM サーバ証明書の作成
以下のCloudFormationテンプレートを利用して、サーバ証明書を作成します。
JSONテンプレート
- acm-test.json
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "ACM test 2016-08-09", "Parameters": { "DomainName": { "Description": "FQDN of the certificate being requested.", "Type": "String", "Default": "" }, "ValidationDomain": { "Description": "The domain to which validation email is sent.", "Type": "String", "Default": "" } }, "Resources": { "ACMCertificate": { "Type": "AWS::CertificateManager::Certificate", "Properties": { "DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]}, "SubjectAlternativeNames": [{ "Ref": "DomainName" }], "DomainValidationOptions": [{ "DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]}, "ValidationDomain": { "Ref": "ValidationDomain" } }] } } } }
CloudFormation操作
テンプレート指定
- ACM設定用のJSONテンプレートを指定します
パラメータ指定
スタック名
- 任意の名称とします
DomainName
- 発行するサーバ証明書のドメイン(FQDN)を指定します。
- コモンネームは「*.DomainName」、ワイルドカード証明書とします。
- ZoneApex、ホスト名省略したアドレスにも対応する証明書とするため、SAN(SubjectAlternativeNames)指定を行います。
ValidationDomain
- メールによるドメイン認証対象となるFQDNを指定します
- 通常「DomainName」と同一の値を指定します
- 証明書の発行対象がサブドメインの場合、親ドメインの指定も可能です
オプション
- 今回は利用しません
確認
ACM ステータス確認
- CloudFromationで作成したサーバ証明書、Statusは「Pending validation」承認待ちである事を確認します
- 承認メールの通知先は、Detailed statusで確認する事が可能です
メール承認
- ドメイン管理者宛に届くメールのリンクより、承認画面を開きます
- ブラウザを開き、承認操作実施します
- ACMのStatus 「Issued」となった事を確認します。
CloudFormation 確認
- CloudFromation 、タイムアウトする前にドメイン承認が実施されると、「CreateComplete」となります。
ELB利用
- ACMで作成した証明書のARNは、「"Ref":リソース名」で取得可能です
- ELBのリスナー設定、SSLCertificateIdに、ACMで作成した証明書のARNを指定して利用します
テンプレート抜粋
"Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Listeners": [ { "InstancePort": "80", "LoadBalancerPort": "443", "Protocol": "HTTPS", "InstanceProtocol": "HTTP", "SSLCertificateId": { "Ref" : "ACMCertificate" } } ] }
CloudFront利用
- CloudFrontはバージニア(us-east-1)で作成したACM証明書を利用します。
- ACMの証明書作成するCloudFormationはバージニアでの実行が必要です。
- AcmCertificateArn にACMで作成した証明書のARNを指定して利用します。
- CloudFrontのSSLは、追加費用不要なSNI(sni-only)を指定します。
テンプレート抜粋
"Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { "ViewerCertificate": { "SslSupportMethod": "sni-only", "AcmCertificateArn": { "Ref": "ACMCertificate"} } } }
まとめ
今回のCloudFromationのアップデート以前、ELB、CloudFrontにACMで発行した サーバ証明書を利用するためには、AWSコンソール、CLIによる手動操作が必須、 作業ミスや、CloudFomationをUpdateStackで更新する際の干渉などにも注意が必要でした。
ACMを利用して、サーバ証明書の有効期限や鍵の管理をAWSに任せる事で、 従来の証明書と比較し、管理、運用に費やす工数も大幅に抑制する事が可能です。 今回のCloudFormationのアップデートにより、更に使いやすくなったACM、ぜひご活用ください。
また、現在ACMのドメイン認証はメールのみ、DNSのTXTレコードなどによる認証が待たれますが、 現在の方式でも、SESのメール受信とLambdaの組み合わせで自動化ができそう。 こちら成功したら、改めて紹介させて頂きたいと思います。
テンプレート例
- Route53、Alias、CNAMEなどのDNSレコード設定は別途必要です
ELB用
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "ACM ELB test 2016-08-09", "Metadata" : { "AWS::CloudFormation::Interface" : { "ParameterGroups" : [ { "Label" : { "default": "ACM Configuration" }, "Parameters" : [ "DomainName", "ValidationDomain" ] }, { "Label" : { "default" : "ELB Configuration" }, "Parameters" : [ "DummyElbSubnet" ] } ], "ParameterLabels" : { "DomainName" : { "default" : "Domain Name" }, "ValidationDomain" : { "default" : "Validation Domain Name" } } } }, "Parameters": { "DomainName": { "Description": "FQDN of the certificate being requested.", "Type": "String", "Default": "" }, "ValidationDomain": { "Description": "The domain to which validation email is sent.", "Type": "String", "Default": "" }, "DummyElbSubnets" : { "Description" : "VPC subnets List (ELB)", "Type" : "List<AWS::EC2::Subnet::Id>" } }, "Resources": { "ACMCertificate": { "Type": "AWS::CertificateManager::Certificate", "Properties": { "DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]}, "SubjectAlternativeNames": [{ "Ref": "DomainName" }], "DomainValidationOptions": [{ "DomainName": { "Fn::Join" : [ "", [ "*.", { "Ref" : "DomainName"} ]]}, "ValidationDomain": { "Ref": "ValidationDomain" } }] } }, "DummyElb": { "DependsOn" : "ACMCertificate", "Type": "AWS::ElasticLoadBalancing::LoadBalancer", "Properties": { "Subnets": { "Ref" : "DummyElbSubnets" }, "Listeners": [ { "InstancePort": "80", "LoadBalancerPort": "443", "Protocol": "HTTPS", "InstanceProtocol": "HTTP", "SSLCertificateId": { "Ref" : "ACMCertificate" } } ], "Instances": [] } } }, "Outputs": { "ACMCertificate": { "Description": "ACMCertificate ARN", "Value": { "Ref": "ACMCertificate" } } } }
CloudFront
- バージニア(us-east-1)で実行
- OriginDomainNameには、CloudFrontのカスタムオリジンとするFQDNを指定します。
{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "ACM CloudFront test 2016-08-09", "Metadata": { "AWS::CloudFormation::Interface": { "ParameterGroups": [ { "Label": { "default": "ACM Configuration" }, "Parameters": [ "DomainName", "ValidationDomain" ] }, { "Label": { "default": "CloudFront Configuration" }, "Parameters": [ "OriginDomainName" ] } ], "ParameterLabels": { "DomainName": { "default": "Domain Name" }, "ValidationDomain": { "default": "Validation Domain Name" }, "OriginDomainName": { "default": "Origin Domain Name" } } } }, "Parameters": { "DomainName": { "Description": "FQDN of the certificate being requested.", "Type": "String", "Default": "" }, "ValidationDomain": { "Description": "The domain to which validation email is sent.", "Type": "String", "Default": "" }, "OriginDomainName": { "Description": "Origin information to specify a custom origin.", "Type": "String", "Default": "" } }, "Resources": { "ACMCertificate": { "Type": "AWS::CertificateManager::Certificate", "Properties": { "DomainName": { "Ref": "DomainName" }, "DomainValidationOptions": [ { "DomainName": { "Ref": "DomainName" }, "ValidationDomain": { "Ref": "ValidationDomain" } } ] } }, "DummyCloudFrontDistribution": { "DependsOn" : "ACMCertificate", "Type": "AWS::CloudFront::Distribution", "Properties": { "DistributionConfig": { "Origins": [ { "DomainName": { "Ref": "OriginDomainName" }, "Id": "DeliveryOrigin", "CustomOriginConfig": { "HTTPPort": "80", "HTTPSPort": "443", "OriginProtocolPolicy": "http-only" } } ], "Enabled": "true", "Comment": { "Ref": "AWS::StackId" }, "Aliases": [{ "Ref": "DomainName"}], "DefaultCacheBehavior": { "TargetOriginId": "DeliveryOrigin", "SmoothStreaming": "false", "ForwardedValues": { "QueryString": "false", "Cookies": { "Forward": "all" } }, "ViewerProtocolPolicy": "allow-all" }, "ViewerCertificate": { "SslSupportMethod": "sni-only", "AcmCertificateArn": { "Ref": "ACMCertificate"} } } } } }, "Outputs": { "ACMCertificate": { "Description": "ACMCertificate ARN", "Value": { "Ref": "ACMCertificate" } } } }